package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.client.utils.StringUtils;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j

public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {


    @Value("${file.oss.web-site}")
    String webSite;

    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    @Autowired
    GreenTextScan greenTextScan;

    @Autowired
    GreenImageScan greenImageScan;

    @Autowired
    AdChannelMapper adChannelMapper;

    @Autowired
    WemediaFeign wemediaFeign;

    @Autowired
    ArticleFeign articleFeign;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        // 1.检查参数
        if (wmNewsId == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "文章Id不能为空奥");
        }

        //2. 获取文章

        ResponseResult<WmNews> wmNewsResult = wemediaFeign.findWmUserById(wmNewsId);
        WmNews wmNews = wmNewsResult.getData();

        //3. 根据文章状态判断   如果为4/8 且发布时间小于等于当前时间则发布
        Short status = wmNews.getStatus();

        if (status.intValue() == 4 || status.intValue() == 8) {
            if (wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
                publishArticle(wmNews);
                return;
            }
        }
        // 3.1 如果状态为1（待审核） 则开始审核
        if (status.intValue() == 1) {
            // 3.2 获取内容 map
            Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);
            // 3.3 DFA敏感词检测\
            boolean isSensitiveScan = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
            if (!isSensitiveScan) {
                return;
            }
            // 3.4 阿里云图文字检测
            boolean isTextScan = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
            if (!isTextScan) {
                return;
            }
            // 3.5 阿里云图片检测
            boolean isImageScan = handleImagesScan((List<String>) contentAndImagesResult.get("images"), wmNews);
            if (!isImageScan) {
                return;
            }
            // 4 全部检测完  如果审核通过 则判断发布时间小于等于当前时间则发布
            if (wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
                publishArticle(wmNews);
                return;
            } else {
                updateWmNews(wmNews, (short) 8, "文章审核通过，待发布");
                return;
            }
        }
    }

    private boolean handleImagesScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        if (images == null && images.size() == 0) {
            return flag;
        }
        images = images.stream().distinct().collect(Collectors.toList());
        try {
            Map map = greenImageScan.imageUrlScan(images);
            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "阿里云审核图片，图片违规");
            }
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "阿里云审核图片,转为人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云审核图片失败，转为人工吧{}", e.getMessage());
            flag = false;
            updateWmNews(wmNews, (short) 3, "阿里云审核图片失败，转为人工吧");
        }
        return flag;
    }

    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            if (map.get("suggestion").equals("block")) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "阿里云检测，其中包含敏感词汇");
            }
            if (map.get("suggestion").equals("review")) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "阿里云检测，需要进行人工审核");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云审核文章失败，请转为人工审核{}", e.getMessage());
            flag = false;
            updateWmNews(wmNews, (short) 3, "阿里云审核文章失败，请转为人工审核");
        }

        return flag;
    }

    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        // 获取敏感词数据
        List<String> sensitives = adSensitiveMapper.findAllSensitive();
        // 用敏感词检测工具检测一下
        SensitiveWordUtil.initMap(sensitives);
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            flag = false;
            updateWmNews(wmNews, (short) 2, "文章中包含敏感词" + map);
        }

        return flag;
    }

    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (responseResult.getCode().intValue() != 0) {
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, responseResult.getErrorMessage());
        }
    }

    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        String content = wmNews.getContent();
        List<Map> contentList = JSON.parseArray(content, Map.class);
        String texts = contentList.stream().filter(map -> map.get("type").equals("text"))
                .map(map -> map.get("value").toString())
                .collect(Collectors.joining("-"));
        // 标题上的内容也要审核
        texts = wmNews.getTitle() + "-" + texts;

        // 处理图片

        List<String> images = contentList.stream().filter(map -> map.get("type").equals("image"))
                .map(map -> map.get("value").toString())
                .collect(Collectors.toList());
        // 封面上的图片也要审核
        String wmNewsImages = wmNews.getImages();
        if (StringUtils.isNotBlank(wmNewsImages)) {
            images.addAll(Arrays.stream(wmNewsImages.split(","))
                    .map(map -> webSite + map).collect(Collectors.toList()));
        }
        Map<String, Object> map = new HashMap();
        map.put("content", texts);
        map.put("images", images);
        return map;
    }

    private void publishArticle(WmNews wmNews) {
        // 1.调用saveArticle方法来将数据存储于三个表中
        ResponseResult responseResult = saveArticle(wmNews);
        if (responseResult.getCode().intValue() != 0) {
            log.error("远程保存apArticle信息失败： {}", responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR, "远程保存apArticle信息失败");
        }
        // 2. 将文章状态改成9
        wmNews.setArticleId((Long) responseResult.getData());
        updateWmNews(wmNews, (short) 9, "发布成功~");
    }

    private ResponseResult saveArticle(WmNews wmNews) {
        // 赋值
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        articleDto.setId(wmNews.getArticleId());
        articleDto.setLayout(wmNews.getType());

        // 如果有频道则赋值频道名字
        if (wmNews.getChannelId() != null) {
            AdChannel adChannel = adChannelMapper.selectById(wmNews.getChannelId());
            articleDto.setChannelName(adChannel.getName());
        }
        articleDto.setFlag((byte) 0);
        articleDto.setWmUserId(wmNews.getUserId());

        // 远程调用实现保存
        return articleFeign.saveArticle(articleDto);
    }
}
